uses {$IFDEF FPC} BaseUnix,Unix, {$ELSE}{$IFDEF VIRTUALPASCAL}unix,{$ENDIF}{$ENDIF}xlib,X,xutil;
type
TCanvasHandle=record
  GC:PXGC;
  Drawable:TDrawable;
end;
PCanvasHandle = ^TCanvasHandle;
procedure TCanvas.SetBrush(AValue: TBrush);
var XGV:TXGCValues;
  p: PCanvasHandle;
begin
  if FBrush=AValue then Exit;
  FBrush:=AValue;
  if (FHandle<>0) and (AValue.FHandle<>0) then
  //Итак, никаких кистей здесь нет, есть только GC.
  begin
    //for speed
    p:=Handle2Ptr(FHandle);
    XGetGCValues(XWinDisplay,p^.GC,-1,@XGV);
    XGV.stipple:=AValue.Bitmap.Handle;
    XGV.foreground:=AValue.Color;
    XChangeGC(XWinDisplay,p^.GC,GCStipple or GCForeground,@XGV);
  end;
end;
procedure TCanvas.SetColor(AValue: TColor);
var XGV:TXGCValues;
    p: PCanvasHandle;
begin
  if FColor=AValue then Exit;
  FColor:=AValue;
  if FHandle=0 then exit;
  p:=Handle2Ptr(FHandle);
  XSetForeground(XWinDisplay,p^.GC,AValue);
end;

procedure TCanvas.SetBackgroundColor(AValue: TColor);

var XGV:TXGCValues;
    p: PCanvasHandle;

begin
  if FBackgroundColor=AValue then Exit;
  FBackgroundColor:=AValue;
  if FHandle=0 then exit;
  p:=Handle2Ptr(FHandle);
  XSetBackground(XWinDisplay,p^.GC,AValue);

end;

function TCanvas.GetPixels(x, y: integer): TColor;

var
  p: PCanvasHandle;
  XGV:TXGCValues;
  img: PXImage;

begin
  if FHandle=0 then exit;
  p:=Handle2Ptr(FHandle);
  img:=XGetImage(XWinDisplay,p^.Drawable,x,y,1,1,AllPlanes,XYPixmap);
  Result:=XGetPixel(img,0,0);
  XDestroyImage(img);

end;

procedure TCanvas.SetFont(AValue: TFont);
var p:PCanvasHandle;
    XGV:TXGCValues;
begin
  if FFont=AValue then Exit;
  FFont:=AValue;
  if (FHandle<>0) and (AValue.FHandle<>0) then

  begin
    p:=Handle2Ptr(FHandle);
    XGetGCValues(XWinDisplay,p^.GC,-1,@XGV);
    XGV.Font:=AValue.FHandle;
    XChangeGC(XWinDisplay,p^.GC,GCFont,@XGV);
  end;
end;

procedure TCanvas.SetPen(AValue: TPen);
var ch:PCanvasHandle;
    XGV:TXGCValues;
begin
  if FPen=AValue then Exit;
  FPen:=AValue;
  FPen.FParent:=self;
  if (FHandle<>0) and (AValue.FHandle<>0) then

  begin
    ch:=Handle2Ptr(FHandle);
    XGetGCValues(XWinDisplay,ch^.GC,-1,@XGV);
    XGV.foreground:=Pen.Color;
    Case Pen.Style of
      psSolid:XGV.line_style:=LineSolid;
      psDash:XGV.line_style:=LineOnOffDash;
      psDashDot:XGV.line_style:=LineDoubleDash;//todo
    end;
    XChangeGC(XWinDisplay,ch^.GC,GCLineStyle or GCForeground,@XGV);
  end;

end;

procedure TCanvas.SetPixels(x, y: integer; AValue: TColor);

var ch:PCanvasHandle;
    XGV:TXGCValues;

begin
  ch:=Handle2Ptr(FHandle);
  XGetGCValues(XWinDisplay,ch^.GC,-1,@XGV);
  XGV.foreground:=AValue;
  XChangeGC(XWinDisplay,ch^.GC,-1,@XGV);
  XDrawPoint(XWinDisplay,ch^.Drawable,ch^.GC,x,y);
  XGV.foreground:=FColor;
  XChangeGC(XWinDisplay,ch^.GC,-1,@XGV);

end;

destructor TCanvas.Destroy;
var ch:PCanvasHandle;
begin
  if FHandle<>0 then
  begin
    ch:=Handle2Ptr(FHandle);
    if FCreated then XFreePixmap(XWinDisplay,ch^.Drawable);
    Dispose(ch);
  end;
  FPen.Free;
  FBrush.Free;
  inherited Destroy;
end;

procedure TCanvas.TextOut(X, Y: integer; const Txt: String);
var ch:PCanvasHandle;
    TI:TXTextItem;
    PCHTxt:PChar;

begin
  ch:=Handle2Ptr(FHandle);
  if ch=nil then exit;
  GetMem(PCHTxt,length(txt)+2);
  strcopy(PCHTxt,@Txt[1]);
  TI.chars:=PCHTxt;//@Txt[1]; //todo txt
  TI.nchars:=length(txt);
  TI.delta:=10;
  TI.font:=None;//From canvas
  XDrawText(XWinDisplay,ch^.Drawable,ch^.GC,X,Y,@TI,1);
  Freemem(PCHTxt,Length(txt)*2);
end;

procedure TCanvas.LineTo(X, Y: integer);
var ch:PCanvasHandle;
begin
  if FHandle=0 then exit;
  ch:=Handle2Ptr(FHandle);
  XDrawLine(XWinDisplay,ch^.Drawable,ch^.GC,OldX,OldY,x,y);
end;

procedure TCanvas.MoveTo(X, Y: integer);
begin
  OldX:=X;OldY:=Y;
end;

procedure TCanvas.Rectangle(x1, y1, x2, y2: integer);
var ch:PCanvasHandle;
begin
  if FHandle=0 then exit;
  ch:=Handle2Ptr(FHandle);
  XDrawRectangle(XWinDisplay,ch^.Drawable,ch^.GC,x1,y1,x2,y2);
end;

procedure TCanvas.FilledRectangle(x1, y1, x2, y2: integer);
var ch:PCanvasHandle;
begin
  if FHandle=0 then exit;
  ch:=Handle2Ptr(FHandle);
  XFillRectangle(XWinDisplay,ch^.Drawable,ch^.GC,x1,y1,x2,y2);
end;

procedure TCanvas.ActualizeWin(WindowHandle: THandle);
var ch:PCanvasHandle;
  GC1: TGC;
  XGV:TXGCValues;
begin
  ch:=Handle2Ptr(FHandle);
  if FCreated then If FHandle<>0 then XFreeGC(XWinDisplay,ch^.GC);
  new(ch);
  ch^.Drawable:=WindowHandle;
  ch^.GC:=XCreateGC(XWinDisplay,WindowHandle,0,nil);
  FHandle:=Ptr2Handle(ch);
  FCreated:=true;
  FGot:=WindowHandle;
  Writeln('My handle is ',FHandle,' while ch is ',LongInt(Ch));
end;

procedure TCanvas.ActualizeMem;

var ch:PCanvasHandle;

begin
  new(ch);
  ch^.Drawable:=XCreatePixmap(XWinDisplay,XRootWindow(XWinDisplay,XDefaultScreen(XWinDisplay)),
           640,480,16);
  Ch^.GC:=XDefaultGC(XWinDisplay,XDefaultScreen(XWinDisplay));
  FHandle:=Ptr2Handle(ch);

end;


{ TBitmap }

function TBitmap.Getbpp: integer;
var
  rw: TXID;
  GC: PXGC;
  x,y:cint;
  w,h,bw,bh,dp:cuint;
  FH1: TXID;
begin
  Result:=0;
  if FHandle<>0 then XGetGeometry(XWinDisplay,FHandle,@rw,@x,@y,@w,@h,@bw,@dp);
  Result:=dp;
end;

function TBitmap.GetScanLine(i: integer): Pointer;
var LnSz:integer;
    Buffer: PByteArray;
begin
  Result:=nil;
  //TODO: fake scanline
end;

function TBitmap.GetHeight: integer;
var
    rw: TXID;
    GC: PXGC;
    x,y:cint;
    w,h,bw,bh,dp:cuint;
    FH1: TXID;


begin
  Result:=0;
  if FHandle<>0 then XGetGeometry(XWinDisplay,FHandle,@rw,@x,@y,@w,@h,@bw,@dp);
  Result:=h;
end;

procedure TBitmap.SetHeight(const AValue: integer);
var Buffer,OldBuffer:PByteArray;
    LnSz,Sz,OldHeight:integer;

    rw: TXID;
    GC: PXGC;
    x,y:cint;
    w,h,bw,bh,dp:cuint;
    FH1: TXID;
begin
  GC:=XDefaultGC(XWinDisplay,XDefaultScreen(XWinDisplay));
  if FHandle<>0 then XGetGeometry(XWinDisplay,FHandle,@rw,@x,@y,@w,@h,@bw,@dp);
  FH1:=XCreatePixmap(XWinDisplay,rw,w,AValue,dp);
  if FHandle<>0 then begin
    XCopyArea(XWinDisplay,AValue,FHandle,GC,0,0,w,min(h,AValue),0,0);
    XFreePixmap(XWinDisplay,FHandle);
  end;
  FHandle:=FH1;
end;

function TBitmap.GetWidth: integer;
var
    rw: TXID;
    GC: PXGC;
    x,y:cint;
    w,h,bw,bh,dp:cuint;
    FH1: TXID;
begin
  Result:=0;
  if FHandle<>0 then XGetGeometry(XWinDisplay,FHandle,@rw,@x,@y,@w,@h,@bw,@dp);
  Result:=w;
end;

procedure TBitmap.SetWidth(const AValue: integer);
var

    rw: TXID;
    GC: PXGC;
    x,y:cint;
    w,h,bw,bh,dp:cuint;
    FH1: TXID;
begin
  GC:=XDefaultGC(XWinDisplay,XDefaultScreen(XWinDisplay));
  if FHandle<>0 then XGetGeometry(XWinDisplay,FHandle,@rw,@x,@y,@w,@h,@bw,@dp);
  FH1:=XCreatePixmap(XWinDisplay,rw,AValue,h,dp);
  if FHandle<>0 then begin
    XCopyArea(XWinDisplay,AValue,FHandle,GC,0,0,Min(w,AValue),h,0,0);
    XFreePixmap(XWinDisplay,FHandle);
  end;
  FHandle:=FH1;
end;

constructor TBitmap.Create;
var
  rw: TXid;
begin
  inherited Create;
  rw:=XDefaultRootWindow(XWinDisplay);
  FHandle:=XCreatePixmap(XWinDisplay,rw,10,10,16);
end;

destructor TBitmap.Destroy;
begin
  if FHandle<>0 then
  XFreePixmap(XWinDisplay,FHandle);

  inherited Destroy;
end;

//TBrush

procedure TBrush.UpdateHandle;
var
  Cnv: TCanvas;
begin

  if FParent=nil then exit;
  if not(FParent is TCanvas) then exit;
  Cnv:=(FParent as TCanvas);
  Cnv.FBrush:=nil;//hack
  Cnv.Brush:=self;
end;

//TPen

procedure TPen.UpdateHandle;
var
  Cnv: TCanvas;
begin
  if FParent=nil then exit;
  if not(FParent is TCanvas) then exit;
  Cnv:=(FParent as TCanvas);
  Cnv.FPen:=nil;//hack
  Cnv.Pen:=self;

end;

procedure TFont.UpdateHandle;
begin
  //TODO
end;
destructor TFont.Destroy;
begin
  inherited Destroy;
end;

var SN:integer;

procedure PrepareGraph;
begin
  XWinDisplay:=XOpenDisplay(nil);
  SN:=XDefaultScreen(XWinDisplay);
  clBlack:=XBlackPixel(XWinDisplay,SN);
  clWhite:=XWhitePixel(XWinDisplay,SN);
end;

procedure FinalGraph;
begin
  XCloseDisplay(XWinDisplay);
end;
